Tutorial 3: Creating custom interactive results for kodak UI

This tutorial is going to discuss how custom .plots files can be created for visualization and design comparisons. The UI website is hosted on GitHub pages and is found at: https://ajvetturini.github.io/kodak/

In general, the .plots files are essentially a json-ified version of a Plotly figure, and any plotly figure you can create using the Python package can be exported to a plots file using similar commands to below

Creating the standard output file

A user interface application has also been developed which allows for design visualization and comparrisons outside of consider a design from a scriptable interface. Here we use the standard output feature to create the output “.plots” file. This file can then be used at https://ajvetturini.github.io/kodak/.

from mango.visualizations.mango_output_visualization import VisualizationObject

# Pass in the results filepath and the output filepath/name for the plots file:
new_viz_object = VisualizationObject(aj1_filepath='./output_folder/my_first_generated_design.aj1',
                                     output_filepath='./output_folder',
                                     ouput_filename_no_extension='kodak_viz_plots'
                                    )

new_viz_object.create_standard_output_single_objective()

Creating a customized output file

While the standard output is “good enough” for some quick visualizations, it may be desirable to create interactive files which communicate more information about your generated design. In this example below, I have considered two of the exact same studies, but in one study I used the repulsion constraint defined in Tutorial 1, and in the other I did not include the custom constraint. In this example, I am interested to see what the difference in generated designs look like, but also how the generative process resulted in the solution: did one take longer than the other, did they follow a similar path, etc.

Below will establish code for how to setup one of these custom figures using plotly.

## Due to dill module, sometimes the custom constraints and objectives can be "ignored"
## resulting in a AttributeError: Can't get attribute ( name ) on <module '__main__'>
## to fix this simply define a blank funciton with that name:
def edge_cutoff_constraint():
    pass
def porosity_objective():
    pass
# First we wil read in the output files:
import dill
fp1 = r"./output_folder/No_cutoff_constraint.aj1"
fp2 = r"./output_folder/Use_cutoff_constraint.aj1"
with open(fp1, 'rb') as f:
    data1 = dill.load(f)
with open(fp2, 'rb') as f:
    data2 = dill.load(f)

print(data1.design_evolution.keys())
print(data2.design_evolution.keys())
dict_keys([0, 196, 357, 521, 664, 801, 915, 1027, 1127, 1225, 1303, 1394, 1444, 1501, 1552, 1604, 1634, 1683, 1724, 1759, 1774, 1791, 1805, 1814, 1825, 1852, 1873, 1892, 1901, 1905, 1909, 1918, 1919, 1921, 1922])
dict_keys([0, 202, 385, 563, 713, 826, 930, 1032, 1146, 1230, 1312, 1373, 1424, 1467, 1522, 1551, 1590, 1625, 1643, 1661, 1678, 1697, 1718, 1740, 1767, 1783, 1784, 1790])
# First lets plot objective function traces:
obj_values1 = data1.optimization_objective_values
obj_values2 = data2.optimization_objective_values

fin_des_data1 = 1922
fin_des_data2 = 1790
# From the above prints we will export the last design to visualize:
final_design1 = data1.design_evolution[fin_des_data1]
final_design2 = data2.design_evolution[fin_des_data2]
# Create hte plotly traces to use:
import numpy as np
import plotly.graph_objs as go

x_vals = np.arange(1, len(obj_values1), 1)
new_trace1 = go.Scatter(x=x_vals, y=obj_values1, mode='lines', line=dict(width=6,
                                                                         color='darkgray',
                                                                         dash='solid'),
                        name='No cutoff', showlegend=True)

x_vals = np.arange(1, len(obj_values2), 1)
new_trace2 = go.Scatter(x=x_vals, y=obj_values2, mode='lines', line=dict(width=6,
                                                                         color='darkblue',
                                                                         dash='dash'),
                        name='Cutoff 5.0 nm', showlegend=True)

# Create the points for the final selected design:
xs = [fin_des_data1, fin_des_data2]
ys = [data1.design_evolution[fin_des_data1][0], data2.design_evolution[1790][0]]

new_trace3 = go.Scatter(x=xs, y=ys, mode='markers', marker=dict(size=16, color='orange',
                                                                line=dict(color='black',
                                                                          width=3)),
                        name='Selected design evolution', showlegend=False)
plot_layout = go.Layout(
    legend=dict(
        x=0.65,  # Set x position to move the legend to the right
        y=1.,  # Set y position to move the legend to the top
    ),
            height=400,

            width=600,
            xaxis=dict(
                linecolor='black',
                linewidth=2,
                mirror=False,
                tickfont=dict(size=24, family='arial', color='black'),
                titlefont=dict(size=28, family='arial', color='black'),
                title='Iteration #',
                showgrid=False,
                gridcolor='black',
                zeroline=False,
            ),
            yaxis=dict(
                linecolor='black',
                linewidth=2,
                mirror=False,
                tickfont=dict(size=24, family='arial', color='black'),
                titlefont=dict(size=28, family='arial', color='black'),
                title='Porosity',
                showgrid=False,
                gridcolor='black',
                zeroline=False,
            ),
            font=dict(family='arial', color='black', size=26),
            plot_bgcolor='rgba(255, 255, 255, 1)',
            paper_bgcolor='rgba(255, 255, 255, 1)',
            autosize=False
        )
# Finally add selectetable designs for export:
from kodak.trace_types import PlotTrace
from plotly.io import from_json
from kodak.kodak_creator import KodakPlots

kodak_plots = KodakPlots()
kodak_plots.standard_2D_layout = plot_layout
window_1_traces = [PlotTrace(plotly_trace=new_trace1, type='scatter'),
                   PlotTrace(plotly_trace=new_trace2, type='scatter'),
                   PlotTrace(plotly_trace=new_trace3, type='scatter')]
window_name = 'Constrained vs Unconstrained Repulsion'
kodak_plots.add_new_plot(traces=window_1_traces, window_title=window_name,
                         description='None')
fig = from_json(kodak_plots.all_plots[window_name]['_data'])

from mango.visualizations import CylindricalRepresentation
camera = dict(
        up=dict(x=0, y=0, z=1),
        center=dict(x=0, y=0, z=0),
        eye=dict(x=1.8, y=0.8, z=0.8)
    )
design_map = {}
idx = 0
scatterXY = [(fin_des_data1, data1.design_evolution[fin_des_data1][0]),
             (fin_des_data2, data2.design_evolution[fin_des_data2][0])]
stored_designs = [data1.design_evolution[fin_des_data1][1], data2.design_evolution[fin_des_data2][1]]
cyl_colors = ['darkgray', 'darkblue']
for xy, des in zip(scatterXY, stored_designs):
    newDes = CylindricalRepresentation(design=des, bounding_box=des.bounding_box, show_bounding_box=True,
                                       excluded_color='rgb(170, 51, 119)', cylinder_color=cyl_colors[idx],
                                       camera_position=camera, display_axes=True, display_background=True)
    nf = newDes.return_figure()
    nf.layout.plot_bgcolor = 'rgba(255, 255, 255, 1)'
    nf.layout.paper_bgcolor = 'rgba(255, 255, 255, 1)'
    nf.layout.scene.zaxis.tickvals = [10, 20, 30, 40, 50]
    nf.show()
    design_map[str(xy)] = nf.to_json()
    del newDes
    idx +=1
kodak_plots.store_interactive_points(design_map=design_map)
## Finally you can export a design as:
kodak_plots.write_json_output(write_directory='./output_folder',
                              savename_no_extension='custom_kodak_plots')